package com.ljph.ljaker.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.ext.interceptor.Restful;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.ljph.jfinal.base.BaseController;
import com.ljph.kit.CommonKit;
import com.ljph.ljaker.enums.UserState;
import com.ljph.jfinal.dto.ApiResult;
import com.ljph.ljaker.app.AppConfig;
import com.ljph.ljaker.interceptor.LoginInterceptor;
import com.ljph.ljaker.model.User;
import com.ljph.ljaker.service.UserService;
import com.ljph.ljaker.validator.UserLoginValidator;
import com.ljph.ljaker.validator.UserSaveValidator;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 用户相关API
 * Created by yuzhou on 16/9/12.
 */
@Before({Restful.class})
public class UserController extends BaseController {

    private static final Logger _log = LoggerFactory.getLogger(UserController.class);

    private UserService service = enhance(UserService.class);

    public void index() {

        List<Object> params = new ArrayList<>();
        StringBuilder filterSql = new StringBuilder(" where 1=1");

        String keywords = getPara("keywords");
        if(StrKit.notBlank(keywords)) {
            filterSql.append(" and username like ?");
            params.add("%" + keywords + "%");
        }

        Integer pageNumber = getParaToInt("pn");
        Long lastTs = getParaToLong("lastTs");

        String tableName =  CommonKit.getTableName(User.class);

        Map<String, Object> data = new HashMap<>();
        if(lastTs == null) { // 新加载数据
            Page<User> page = User.dao.paginate(1, 10, "select *", " from " + tableName
                    + filterSql.toString()
                    + " order by updateTime desc", params.toArray());

            page.getList().forEach((user) -> {
                user.setStateLabel(UserState.stateOf(user.getState()).getLabel());
            });
            data.put("page", page);
            renderJson(new ApiResult(true).setData(data).setTs(new Date()));

        } else {

            // 获取更新数据 TODO: 更新的数据统计中需要剔除用户已经在本地添加/修改的数据

            List<Object> countParams = new ArrayList<>();
            countParams.addAll(params);
            StringBuilder countFilterSql = new StringBuilder(filterSql.toString());

            countFilterSql.append(" and updateTime > ?");
            countParams.add(new Date(lastTs));

            String localUpdated = getPara("updated");
            if(StrKit.notBlank(localUpdated)) {
                JSONObject jsonObject = JSON.parseObject(localUpdated);
                jsonObject.entrySet().forEach((entry) -> {
                    _log.debug("Exclude id: {}, updateTime: {}", entry.getKey(), entry.getValue());
                    countFilterSql.append(" and !(id = ? and updateTime = ?)");
                    countParams.add(entry.getKey());
                    countParams.add(new Date(Long.valueOf(entry.getValue().toString())));
                });
            }

            Long updated = Db.queryLong("select count(*) from " + tableName
                    + countFilterSql.toString(), countParams.toArray());

            data.put("updated", updated);

            if(pageNumber != null) {
                filterSql.append(" and updateTime <= ?");
                params.add(new Date(lastTs));
                Page<User> page = User.dao.paginate(pageNumber, 10, "select *", " from " + tableName
                        + filterSql.toString()
                        + " order by updateTime desc", params.toArray());

                page.getList().forEach((user) -> {
                    user.setStateLabel(UserState.stateOf(user.getState()).getLabel());
                });
                data.put("page", page);
            }

            renderJson(new ApiResult(true).setData(data));
        }
    }

    /**
     * 保存一个新的用户
     */
    @Before({ UserSaveValidator.class })
    public void save() {
        _log.debug("Save a new user");

        ApiResult result = new ApiResult();

        try{
            User user = getAttr("user");
            Date now = new Date();
            // 对用户的密码进行MD5混淆加密
            String salt = CommonKit.uuid();
            user.setSalt(salt);
            user.setPassword(DigestUtils.md5Hex( DigestUtils.md5Hex(user.getPassword())) + salt );
            user.setCreateTime(now);
            user.setUpdateTime(now);
            user.setState(UserState.NORMAL);

            if(service.save(user)) {
                result.setOk(true).setData(user);
            } else {
                result.setOk(false).setError("保存用户失败");
            }
        }
        catch (Exception e){
            result.setOk(false).setError(e);
            _log.error("Fail to save user", e);
        }

        renderJson(result);
    }

    public void show(){
        Long uid = getParaToLong();
        User user = User.dao.findById(uid);
        ApiResult result = new ApiResult();

        if(user == null) {
            renderJson(result.setOk(false).setError("用户找不到"));
            return;
        }
        user.setStateLabel(UserState.stateOf(user.getState()).getLabel());
        renderJson(result.setOk(true).setData(user));
    }

    @Clear({Restful.class})
    public void update(){
        ApiResult result = new ApiResult();

        Long uid = getParaToLong();
        User user = User.dao.findById(uid);
        if(user == null) {
            renderJson(result.setOk(false).setError("用户" + uid + "不存在"));
            return;
        }

        String username = getPara("username");
        if(username != null && User.dao.findByUsername(username) != null) {
            renderJson(result.setOk(false).setError("用户名" + username + "已经被使用"));
            return;
        }

        try {

            Enumeration<String> cols = getParaNames();

            HashMap<String, Object> changed = new HashMap<String, Object>();
            while (cols.hasMoreElements()) {
                String key = cols.nextElement();
                if (key.equalsIgnoreCase("password")) {
                    String salt = CommonKit.uuid();
                    changed.put("salt", salt);
                    changed.put("password", DigestUtils.md5Hex(DigestUtils.md5Hex(getPara("password"))) + salt);
                    continue;
                }
                changed.put(key, getPara(key));
            }

            if (service.update(user, changed)) {
                user = User.dao.findById(uid);
                user.setStateLabel(UserState.stateOf(user.getState()).getLabel());
                result.setOk(true).setData(user);
            } else {
                result.setOk(false).setError("用户更新失败");
            }
        } catch (Exception e) {
            result.setOk(false).setError(e);
            _log.error("Fail to update user", e);
        }

        renderJson(result);
    }

    @Clear({LoginInterceptor.class, Restful.class})
    @Before({UserLoginValidator.class})
    public void login(){
        User user = getAttr("user");
        setSessionAttr(AppConfig.SESSION_USER, user);
        if(getParaToBoolean("remember",false)){
            setCookie(AppConfig.COOKIE_USER, user.getId().toString(), AppConfig.COOKIE_DURATION);
        }

        renderJson(new ApiResult<User>(true, user));
    }

    @Clear({Restful.class})
    public void me(){
        User user = getSessionAttr(AppConfig.SESSION_USER);
        renderJson(new ApiResult<User>(true, user));
    }

}
